# -*- coding: utf-8 -*-
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from typing import Optional, List
import os
import shutil
from datetime import datetime

from database.database import get_db
from crud import ota as ota_crud
from schemas.ota import (
    OTAFirmwareCreate, 
    OTAFirmwareUpdate, 
    OTAFirmwareResponse, 
    OTAFirmwareUploadResponse,
    OTAFirmwareListResponse,
    OTAFirmwareVersionResponse,
    FirmwareInfo
)
from models.ota import OTAFirmware

# 创建路由器
ota_router = APIRouter(prefix="/ota", tags=["OTA固件管理"])

# 固件文件存储目录
FIRMWARE_UPLOAD_DIR = "uploaded_files/firmware"
os.makedirs(FIRMWARE_UPLOAD_DIR, exist_ok=True)


@ota_router.post("/upload", response_model=OTAFirmwareUploadResponse)
async def upload_firmware(
    # CM3程序信息
    cm3_version: Optional[str] = Form(None, description="CM3版本号"),
    cm3_version_code: Optional[int] = Form(None, description="CM3版本代码"),
    cm3_changelog: Optional[str] = Form(None, description="CM3更新日志"),
    cm3_file: Optional[UploadFile] = File(None, description="CM3固件文件"),
    
    # DSP程序信息
    dsp_version: Optional[str] = Form(None, description="DSP版本号"),
    dsp_version_code: Optional[int] = Form(None, description="DSP版本代码"),
    dsp_changelog: Optional[str] = Form(None, description="DSP更新日志"),
    dsp_file: Optional[UploadFile] = File(None, description="DSP固件文件"),
    
    # 备注信息
    remark: Optional[str] = Form(None, description="备注信息"),
    
    db: Session = Depends(get_db)
):
    """上传OTA固件文件 - 支持CM3和DSP程序单独或一起上传"""
    try:
        # 验证至少有一个程序
        if not cm3_file and not dsp_file:
            raise HTTPException(status_code=400, detail="至少需要上传一个固件文件")
        
        # 验证文件类型
        allowed_extensions = [".bin", ".hex", ".elf", ".img"]
        
        cm3_file_info = None
        dsp_file_info = None
        
        # 处理CM3文件
        if cm3_file:
            if not cm3_version or not cm3_version_code:
                raise HTTPException(status_code=400, detail="CM3程序需要提供版本号和版本代码")
            
            file_extension = os.path.splitext(cm3_file.filename)[1].lower()
            if file_extension not in allowed_extensions:
                raise HTTPException(status_code=400, detail=f"CM3文件类型不支持，支持的类型: {', '.join(allowed_extensions)}")
            
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            file_name = f"cm3_{cm3_version}_{timestamp}{file_extension}"
            file_path = os.path.join(FIRMWARE_UPLOAD_DIR, file_name)
            
            with open(file_path, "wb") as buffer:
                shutil.copyfileobj(cm3_file.file, buffer)
            
            cm3_file_info = {
                'file_name': file_name,
                'file_path': file_path,
                'file_size': os.path.getsize(file_path)
            }
        
        # 处理DSP文件
        if dsp_file:
            if not dsp_version or not dsp_version_code:
                raise HTTPException(status_code=400, detail="DSP程序需要提供版本号和版本代码")
            
            file_extension = os.path.splitext(dsp_file.filename)[1].lower()
            if file_extension not in allowed_extensions:
                raise HTTPException(status_code=400, detail=f"DSP文件类型不支持，支持的类型: {', '.join(allowed_extensions)}")
            
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            file_name = f"dsp_{dsp_version}_{timestamp}{file_extension}"
            file_path = os.path.join(FIRMWARE_UPLOAD_DIR, file_name)
            
            with open(file_path, "wb") as buffer:
                shutil.copyfileobj(dsp_file.file, buffer)
            
            dsp_file_info = {
                'file_name': file_name,
                'file_path': file_path,
                'file_size': os.path.getsize(file_path)
            }
        
        # 创建固件记录
        firmware_data = OTAFirmwareCreate(
            cm3_version=cm3_version,
            cm3_version_code=cm3_version_code,
            cm3_changelog=cm3_changelog,
            dsp_version=dsp_version,
            dsp_version_code=dsp_version_code,
            dsp_changelog=dsp_changelog,
            remark=remark
        )
        
        firmware = ota_crud.create_ota_firmware(
            db=db,
            firmware=firmware_data,
            cm3_file_info=cm3_file_info,
            dsp_file_info=dsp_file_info
        )
        
        return OTAFirmwareUploadResponse(
            success=True,
            message="固件上传成功",
            firmware=OTAFirmwareResponse.from_orm(firmware)
        )
        
    except Exception as e:
        # 如果出错，删除已上传的文件
        if 'cm3_file_info' in locals() and cm3_file_info and os.path.exists(cm3_file_info['file_path']):
            os.remove(cm3_file_info['file_path'])
        if 'dsp_file_info' in locals() and dsp_file_info and os.path.exists(dsp_file_info['file_path']):
            os.remove(dsp_file_info['file_path'])
        raise HTTPException(status_code=500, detail=f"上传失败: {str(e)}")


@ota_router.get("/download/latest/{firmware_type}", response_class=FileResponse)
async def download_latest_firmware(firmware_type: str, db: Session = Depends(get_db)):
    """下载最新版本的指定类型固件"""
    if firmware_type not in ["cm3", "dsp"]:
        raise HTTPException(status_code=400, detail="固件类型必须是 cm3 或 dsp")
    
    # 根据类型获取最新固件
    if firmware_type == "cm3":
        firmware = ota_crud.get_latest_cm3_firmware(db)
    else:
        firmware = ota_crud.get_latest_dsp_firmware(db)
    
    if not firmware:
        raise HTTPException(status_code=404, detail=f"未找到 {firmware_type} 类型的固件")
    
    # 根据类型获取文件信息
    if firmware_type == "cm3":
        if not firmware.cm3_file_path:
            raise HTTPException(status_code=404, detail="CM3固件文件不存在")
        file_path = firmware.cm3_file_path
        file_name = firmware.cm3_file_name
    else:
        if not firmware.dsp_file_path:
            raise HTTPException(status_code=404, detail="DSP固件文件不存在")
        file_path = firmware.dsp_file_path
        file_name = firmware.dsp_file_name
    
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="固件文件不存在")
    
    return FileResponse(
        path=file_path,
        filename=file_name,
        media_type='application/octet-stream'
    )


@ota_router.get("/download/{firmware_id}/{firmware_type}", response_class=FileResponse)
async def download_firmware(firmware_id: int, firmware_type: str, db: Session = Depends(get_db)):
    """下载指定固件的CM3或DSP程序"""
    if firmware_type not in ["cm3", "dsp"]:
        raise HTTPException(status_code=400, detail="固件类型必须是 cm3 或 dsp")
    
    firmware = ota_crud.get_ota_firmware_by_id(db, firmware_id)
    if not firmware:
        raise HTTPException(status_code=404, detail="固件不存在")
    
    # 根据类型获取文件信息
    if firmware_type == "cm3":
        if not firmware.cm3_file_path:
            raise HTTPException(status_code=404, detail="CM3固件文件不存在")
        file_path = firmware.cm3_file_path
        file_name = firmware.cm3_file_name
    else:
        if not firmware.dsp_file_path:
            raise HTTPException(status_code=404, detail="DSP固件文件不存在")
        file_path = firmware.dsp_file_path
        file_name = firmware.dsp_file_name
    
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="固件文件不存在")
    
    return FileResponse(
        path=file_path,
        filename=file_name,
        media_type='application/octet-stream'
    )


@ota_router.get("/latest", response_model=dict)
async def get_latest_firmware_info(db: Session = Depends(get_db)):
    """获取最新CM3和DSP固件版本信息及下载链接"""
    try:
        # 获取最新的CM3和DSP固件
        cm3_firmware = ota_crud.get_latest_cm3_firmware(db)
        dsp_firmware = ota_crud.get_latest_dsp_firmware(db)
        
        result = {
            "success": True,
            "message": "获取最新固件信息成功",
            "data": {
                "cm3": None,
                "dsp": None
            }
        }
        
        # CM3信息
        if cm3_firmware and cm3_firmware.cm3_version:
            result["data"]["cm3"] = {
                "version": cm3_firmware.cm3_version,
                "version_code": cm3_firmware.cm3_version_code,
                "file_name": cm3_firmware.cm3_file_name,
                "file_size": cm3_firmware.cm3_file_size,
                "changelog": cm3_firmware.cm3_changelog,
                "created_at": cm3_firmware.created_at.isoformat() if cm3_firmware.created_at else None,
                "download_url": f"/ota/download/{cm3_firmware.id}/cm3",
                "latest_download_url": "/ota/download/latest/cm3"
            }
        
        # DSP信息
        if dsp_firmware and dsp_firmware.dsp_version:
            result["data"]["dsp"] = {
                "version": dsp_firmware.dsp_version,
                "version_code": dsp_firmware.dsp_version_code,
                "file_name": dsp_firmware.dsp_file_name,
                "file_size": dsp_firmware.dsp_file_size,
                "changelog": dsp_firmware.dsp_changelog,
                "created_at": dsp_firmware.created_at.isoformat() if dsp_firmware.created_at else None,
                "download_url": f"/ota/download/{dsp_firmware.id}/dsp",
                "latest_download_url": "/ota/download/latest/dsp"
            }
        
        return result
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取最新固件信息失败: {str(e)}")


@ota_router.get("/latest/{firmware_type}", response_model=dict)
async def get_latest_firmware_by_type(firmware_type: str, db: Session = Depends(get_db)):
    """获取指定类型的最新固件信息及下载链接"""
    if firmware_type not in ["cm3", "dsp"]:
        raise HTTPException(status_code=400, detail="固件类型必须是 cm3 或 dsp")
    
    try:
        # 根据类型获取最新固件
        if firmware_type == "cm3":
            firmware = ota_crud.get_latest_cm3_firmware(db)
            if not firmware or not firmware.cm3_version:
                raise HTTPException(status_code=404, detail="未找到CM3固件")
            
            result = {
                "success": True,
                "message": "获取最新CM3固件信息成功",
                "data": {
                    "firmware_type": "cm3",
                    "version": firmware.cm3_version,
                    "version_code": firmware.cm3_version_code,
                    "file_name": firmware.cm3_file_name,
                    "file_size": firmware.cm3_file_size,
                    "changelog": firmware.cm3_changelog,
                    "created_at": firmware.created_at.isoformat() if firmware.created_at else None,
                    "download_url": f"/ota/download/{firmware.id}/cm3",
                    "latest_download_url": "/ota/download/latest/cm3"
                }
            }
        else:
            firmware = ota_crud.get_latest_dsp_firmware(db)
            if not firmware or not firmware.dsp_version:
                raise HTTPException(status_code=404, detail="未找到DSP固件")
            
            result = {
                "success": True,
                "message": "获取最新DSP固件信息成功",
                "data": {
                    "firmware_type": "dsp",
                    "version": firmware.dsp_version,
                    "version_code": firmware.dsp_version_code,
                    "file_name": firmware.dsp_file_name,
                    "file_size": firmware.dsp_file_size,
                    "changelog": firmware.dsp_changelog,
                    "created_at": firmware.created_at.isoformat() if firmware.created_at else None,
                    "download_url": f"/ota/download/{firmware.id}/dsp",
                    "latest_download_url": "/ota/download/latest/dsp"
                }
            }
        
        return result
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取最新{firmware_type.upper()}固件信息失败: {str(e)}")


@ota_router.get("/check-update", response_model=dict)
async def check_firmware_update(
    current_cm3_version: Optional[str] = None,
    current_dsp_version: Optional[str] = None,
    db: Session = Depends(get_db)
):
    """检查固件更新 - 比较当前版本与最新版本"""
    try:
        from crud.ota import compare_versions
        
        result = {
            "success": True,
            "message": "检查更新完成",
            "data": {
                "cm3": {
                    "has_update": False,
                    "current_version": current_cm3_version,
                    "latest_version": None,
                    "update_available": False
                },
                "dsp": {
                    "has_update": False,
                    "current_version": current_dsp_version,
                    "latest_version": None,
                    "update_available": False
                }
            }
        }
        
        # 检查CM3更新
        if current_cm3_version:
            cm3_firmware = ota_crud.get_latest_cm3_firmware(db)
            if cm3_firmware and cm3_firmware.cm3_version:
                latest_cm3_version = cm3_firmware.cm3_version
                has_update = compare_versions(latest_cm3_version, current_cm3_version) > 0
                
                result["data"]["cm3"] = {
                    "has_update": True,
                    "current_version": current_cm3_version,
                    "latest_version": latest_cm3_version,
                    "update_available": has_update,
                    "version_code": cm3_firmware.cm3_version_code,
                    "file_name": cm3_firmware.cm3_file_name,
                    "file_size": cm3_firmware.cm3_file_size,
                    "changelog": cm3_firmware.cm3_changelog,
                    "download_url": f"/ota/download/{cm3_firmware.id}/cm3",
                    "latest_download_url": "/ota/download/latest/cm3"
                }
        
        # 检查DSP更新
        if current_dsp_version:
            dsp_firmware = ota_crud.get_latest_dsp_firmware(db)
            if dsp_firmware and dsp_firmware.dsp_version:
                latest_dsp_version = dsp_firmware.dsp_version
                has_update = compare_versions(latest_dsp_version, current_dsp_version) > 0
                
                result["data"]["dsp"] = {
                    "has_update": True,
                    "current_version": current_dsp_version,
                    "latest_version": latest_dsp_version,
                    "update_available": has_update,
                    "version_code": dsp_firmware.dsp_version_code,
                    "file_name": dsp_firmware.dsp_file_name,
                    "file_size": dsp_firmware.dsp_file_size,
                    "changelog": dsp_firmware.dsp_changelog,
                    "download_url": f"/ota/download/{dsp_firmware.id}/dsp",
                    "latest_download_url": "/ota/download/latest/dsp"
                }
        
        return result
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"检查更新失败: {str(e)}")


@ota_router.get("/version", response_model=OTAFirmwareVersionResponse)
async def get_all_firmware_versions(db: Session = Depends(get_db)):
    """获取最新固件的版本信息 - 按版本号排序"""
    # 分别获取CM3和DSP的最新版本（使用版本号比较）
    cm3_firmware = ota_crud.get_latest_cm3_firmware(db)
    dsp_firmware = ota_crud.get_latest_dsp_firmware(db)
    
    cm3_info = None
    dsp_info = None
    
    if cm3_firmware and cm3_firmware.cm3_version:
        cm3_info = FirmwareInfo(
            version=cm3_firmware.cm3_version,
            version_code=cm3_firmware.cm3_version_code,
            file_name=cm3_firmware.cm3_file_name,
            file_path=cm3_firmware.cm3_file_path,
            file_size=cm3_firmware.cm3_file_size,
            changelog=cm3_firmware.cm3_changelog
        )
    
    if dsp_firmware and dsp_firmware.dsp_version:
        dsp_info = FirmwareInfo(
            version=dsp_firmware.dsp_version,
            version_code=dsp_firmware.dsp_version_code,
            file_name=dsp_firmware.dsp_file_name,
            file_path=dsp_firmware.dsp_file_path,
            file_size=dsp_firmware.dsp_file_size,
            changelog=dsp_firmware.dsp_changelog
        )
    
    # 使用最新的固件记录作为基础信息
    latest_firmware = cm3_firmware if cm3_firmware else dsp_firmware
    if not latest_firmware:
        raise HTTPException(status_code=404, detail="未找到任何固件")
    
    return OTAFirmwareVersionResponse(
        cm3_info=cm3_info,
        dsp_info=dsp_info,
        is_active=latest_firmware.is_active,
        created_at=latest_firmware.created_at
    )


@ota_router.get("/changelog/{firmware_type}")
async def get_firmware_changelog(firmware_type: str, db: Session = Depends(get_db)):
    """获取指定类型的最新固件更新日志"""
    if firmware_type not in ["cm3", "dsp"]:
        raise HTTPException(status_code=400, detail="固件类型必须是 cm3 或 dsp")
    
    # 根据类型获取最新固件
    if firmware_type == "cm3":
        firmware = ota_crud.get_latest_cm3_firmware(db)
        if not firmware or not firmware.cm3_version:
            raise HTTPException(status_code=404, detail="未找到CM3固件")
        return {
            "firmware_type": "cm3",
            "version": firmware.cm3_version,
            "version_code": firmware.cm3_version_code,
            "changelog": firmware.cm3_changelog,
            "created_at": firmware.created_at
        }
    else:
        firmware = ota_crud.get_latest_dsp_firmware(db)
        if not firmware or not firmware.dsp_version:
            raise HTTPException(status_code=404, detail="未找到DSP固件")
        return {
            "firmware_type": "dsp",
            "version": firmware.dsp_version,
            "version_code": firmware.dsp_version_code,
            "changelog": firmware.dsp_changelog,
            "created_at": firmware.created_at
        }


@ota_router.get("/list", response_model=OTAFirmwareListResponse)
async def get_firmware_list(
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db)
):
    """获取固件列表"""
    firmwares = ota_crud.get_firmware_list(db, skip, limit)
    total = ota_crud.get_firmware_count(db)
    
    return OTAFirmwareListResponse(
        total=total,
        items=[OTAFirmwareResponse.from_orm(firmware) for firmware in firmwares]
    )


@ota_router.put("/{firmware_id}", response_model=OTAFirmwareResponse)
async def update_firmware(
    firmware_id: int,
    firmware_update: OTAFirmwareUpdate,
    db: Session = Depends(get_db)
):
    """更新固件信息"""
    firmware = ota_crud.update_ota_firmware(db, firmware_id, firmware_update)
    if not firmware:
        raise HTTPException(status_code=404, detail="固件不存在")
    
    return OTAFirmwareResponse.from_orm(firmware)


@ota_router.delete("/{firmware_id}")
async def delete_firmware(firmware_id: int, db: Session = Depends(get_db)):
    """删除固件"""
    firmware = ota_crud.get_ota_firmware_by_id(db, firmware_id)
    if not firmware:
        raise HTTPException(status_code=404, detail="固件不存在")
    
    # 删除文件
    if firmware.cm3_file_path and os.path.exists(firmware.cm3_file_path):
        os.remove(firmware.cm3_file_path)
    if firmware.dsp_file_path and os.path.exists(firmware.dsp_file_path):
        os.remove(firmware.dsp_file_path)
    
    # 删除数据库记录
    success = ota_crud.delete_ota_firmware(db, firmware_id)
    if not success:
        raise HTTPException(status_code=500, detail="删除失败")
    
    return {"message": "固件删除成功"} 